#pragma once

#include "Policies.h"

template <
class T,
template <class> class BufferFullPolicy = AddOverwrite,
template <class> class BufferEmptyPolicy = EmptyDefault
>
class RingBuffer : public BufferFullPolicy<T>, public BufferEmptyPolicy<T>
{
public:
	RingBuffer(unsigned int s):
	  start(0), end(s-1), counter(0), size(s), buffer(new T[s]) { }

	~RingBuffer(void)
	{
		if(buffer != 0)
		{
			delete[] buffer;
			buffer = 0;
		}
	}

	void add(const T &data)
	{
		if(isFull() && !BufferFullPolicy<T>::insertData())
			return;

		buffer[start] = data;
		incr();
	}
	T get(unsigned int element)
	{
		if(element > size)
			throw("out of bounds");

		if(isEmpty())
		{
			return BufferEmptyPolicy<T>::get();
		}
		return buffer[element];
	}
	void print()
	{
		if(isEmpty())
			return;

		std::cout << "******************************************" << std::endl;
		std::cout << "*                 Buffer                 *" << std::endl;
		std::cout << "******************************************" << std::endl;
		for(unsigned int i=0; i<size; i++)
		{
			if(i == start)
				std::cout << "[" << buffer[i] << "]" << ", ";
			else if(i == end)
				std::cout << "{" << buffer[i] << "}" << ", ";
			else
				std::cout << buffer[i] << ", ";
		}
		std::cout << std::endl << std::endl;
	}

private:
	bool isFull()
	{
		if(counter >= size)
			return true;
		else
			return false;
	}
	bool isEmpty()
	{
		return counter == 0;
	}
	void incr()
	{
		end = (end + 1) % size;
		start = (start + 1) % size;
		counter++;
	}

private:
	unsigned int start, end, counter;
	const unsigned int size;
	T* buffer;
};

